package com.workingpub.commons.jdbc.builder.internal;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBElement;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.workingpub.commons.jdbc.builder.BuildContext;
import com.workingpub.commons.jdbc.builder.LogicResolver;
import com.workingpub.commons.jdbc.builder.ResolverFactory;
import com.workingpub.commons.jdbc.builder.SqlParamBuilder;

@Service
public class DefaultResolverFactory implements ResolverFactory, ApplicationContextAware {
	private ApplicationContext applicationContext;

	@Autowired
	private List<LogicResolver> logicResolvers;

	@Override
	public List<Object> resolve(BuildContext buildContext, Object[] entries) {
		Assert.notNull(buildContext, "Build context can't be null.");
		if (null == entries || entries.length == 0) {
			return null;
		}
		List<Object> results = new ArrayList<Object>();
		for (Object entry : entries) {
			results.addAll(resolve(buildContext, entry));
		}
		return results;
	}

	@Override
	public List<Object> resolve(BuildContext buildContext, Object entry) {
		Assert.notNull(buildContext, "Build context can't be null.");
		if (null == entry) {
			return null;
		}
		List<Object> results = new ArrayList<Object>();
		if (entry instanceof String) {
			String sqlSegment = StringUtils.trimWhitespace((String) entry);
			if (StringUtils.hasText(sqlSegment)) {
				sqlSegment = SqlParamBuilder.build(sqlSegment, buildContext);
				results.add(" " + sqlSegment);
			}
		} else {
			Object buildEntry = null;
			if (entry instanceof JAXBElement) {
				buildEntry = ((JAXBElement<?>) entry).getValue();
			} else {
				buildEntry = entry;
			}
			for (LogicResolver resolver : getLogicResolvers()) {
				List<Object> entryContext = resolver.getContext(buildContext, buildEntry);
				if (!CollectionUtils.isEmpty(entryContext)) {
					results.addAll(entryContext);
					break;
				}
			}
		}
		return results;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	private List<LogicResolver> getLogicResolvers() {
		if (null == logicResolvers) {
			logicResolvers = new ArrayList<LogicResolver>();
			Map<String, LogicResolver> resolverMap = applicationContext.getBeansOfType(LogicResolver.class);
			if (!CollectionUtils.isEmpty(resolverMap)) {
				logicResolvers.addAll(resolverMap.values());
			}
		}
		return logicResolvers;
	}
}
